﻿/*CSSHEPHERD JAVASCRIPT STYLESHEET MANIPULATION TOOL*/
/*
   License: http://www.gnu.org/licenses/lgpl-3.0.txt
   "CSS in its stylesheet, all right with the world"
   
   developed by KaisarCode.com (http://kaisarcode.com/)
   
 * @title: CSShepherd
 * @description:  Crossbrowser javascript stylesheet manpulation tool
 * @implementation: For documentation go to http://code.google.com/p/csshepherd/
*/
kcCSShepherd=function(){
	this.sheet=function(selector,value,index){
		var kc_sheetmethod=this.sheet;
		var kc_stylesheets=document.styleSheets;
		var kc_sheet={}
		
		var kccnt=0;
		
		
		for(var kci=0;kci<kc_stylesheets.length;kci++){
			kc_stylesheets[kci].index=kci;
		}
		
		/*DETECT STYLESHEET*/
		switch(typeof(selector)){
			case "undefined":
				for(var kci=0;kci<kc_stylesheets.length;kci++){
					kc_sheet[kci]=kc_stylesheets[kci];
					kccnt++;
				}
			break;
			case "number":
				kc_sheet[0]=kc_stylesheets[selector];
				kccnt++;
			break;
			case "string":
				
				/*Select Stylesheets by HREF match function*/
				function selectByAttr(kcstrict,kcattr,kcvalue,kcnum){
					var kc_parent=null;
					for(var kci=0;kci<kc_stylesheets.length;kci++){
						kc_stylesheets[kci].owningElement ? kc_parent=kc_stylesheets[kci].owningElement : kc_parent=kc_stylesheets[kci].ownerNode;
						/*Validate for attribute or href search*/
						try{
							var thisattrvalidate=false;
							if(kcstrict){
								thisattrvalidate=kc_parent.attributes[kcattr].value==kcvalue;
							}else{
								thisattrvalidate=kc_parent.attributes[kcattr].value.match(kcvalue);
							}
							if(thisattrvalidate){
								if(typeof(kcnum)=="undefined"){
									kc_sheet[kccnt]=kc_stylesheets[kci];
									kccnt++;
								}else{
									if(typeof(kcnum)=="number"){
										if(kci==kcnum){
											kc_sheet[kccnt]=kc_stylesheets[kci];
											kccnt++;
										}
									}
								}
							}
						}catch(err){}
					}
				}
				if(typeof(value)=="undefined"){
					/*Return all sheets with that selector as part of its HREF*/
					selectByAttr(false,"href",selector);
				}else{
					if(typeof(value)=="number"){
						/*Return a specific sheet with that selector as part of its HREF*/
						selectByAttr(false,"href",selector,value);
					}
					/*Select Stylesheets by Attribute/Value*/
					else if(typeof(value)=="string"){
						/*Return all sheets with that pair of attribute-value*/
						if(typeof(index)=="undefined"){
							selectByAttr(true,selector,value);
						}
						/*Return a specific sheet with that pair of attribute-value*/
						else{
							selectByAttr(true,selector,value,index);
						}
					}
				}
			break;
		}
		
		
		/*
		@title: Selected Stylesheets Length
		@description: length of all selected stylesheets
		@return: number
		*/
		kc_sheet.length=kccnt;
		
		
		/*
		@title: Stylesheets Index
		@description: return selected sheets Stack position index
		@return: object with all position numbers
		*/
		kc_sheet.index=function(index){
			var kc_index={}
			var kccnt=0;
			for(var kci=0;kci<kc_sheet.length;kci++){
				if(typeof(index)=="undefined"){
					kc_index[kccnt]=kc_sheet[kci].index;
					kccnt++;
				}else if(kc_sheet[kci].index == index){
					kc_index[kccnt]=kc_sheet[kci].index;
					kccnt++;
				}
			}
			return kc_index;
		}
		
		
		/*
		@title: Stylesheets Parent
		@description: return selected sheets Owner Node
		@return: object with HTML DOM elements
		*/
		kc_sheet.parent=function(index){
			var kc_parent={}
			var kccnt=0;
			for(var kci=0;kci<kc_sheet.length;kci++){
				if(typeof(index)=="undefined"){
					kc_sheet[kci].owningElement ? kc_parent[kccnt]=kc_sheet[kci].owningElement : kc_parent[kccnt]=kc_sheet[kci].ownerNode;
					kccnt++;
				}else if(kci==index){
					kc_sheet[kci].owningElement ? kc_parent[kccnt]=kc_sheet[kci].owningElement : kc_parent[kccnt]=kc_sheet[kci].ownerNode;
					kccnt++;
				}
			}
			return kc_parent;
		}
		
		/*
		@title: Disable/Enable Stylesheets
		@description: disable/enable selected sheets
		@params: boolean
		@return: object with boolean results
		*/
		kc_sheet.disabled=function(kc_bool){
			var kcdisable={}
			for(var kci=0;kci<kc_sheet.length;kci++){
				if(typeof(kc_bool)!="undefined"){
					if(kc_bool){
						kc_sheet[kci].disabled=true;
					}else{
						kc_sheet[kci].disabled=false;
					}
				}
				kcdisable[kci]=kc_sheet[kci].disabled;
			}
			return kcdisable;
		}
		
		/*
		@title: set CSS Rule
		@description: add a new CSS Rule
		@params: selector [string]
				 declaration
				 index [number]
		@return: the new created rules
		*/
		kc_sheet.set=function(selector,declaration,index){
			var kcrules={};
			for(var kci=0;kci<kc_sheet.length;kci++){
				if(typeof(index)=="undefined"){
					if(kc_sheet[kci].cssRules){
						index=kc_sheet[kci].cssRules.length;
					}else{
						index=kc_sheet[kci].rules.length;
					}
					var kc_auto_index=true;
				}
				if(kc_sheet[kci].cssRules){
					if(typeof(declaration)=="string"){
						kc_sheet[kci].insertRule(selector+"{"+declaration+"}",index);
					}else if(typeof(declaration)=="object"){
						var kc_newcreatedrulenum=kc_sheet[kci].insertRule(selector+"{ }",index);
						for(var kcd in declaration){
							kc_sheet[kci].cssRules[kc_newcreatedrulenum].style[kcd]=declaration[kcd];
						}
					}
				}else{
					if(typeof(declaration)=="string"){
						kc_sheet[kci].addRule(selector,declaration,index);
					}else if(typeof(declaration)=="object"){
						var kc_newcreatedrulenum=kc_sheet[kci].addRule(selector," ",index);
						for(var kcd in declaration){
							kc_sheet[kci].rules[kc_newcreatedrulenum].style[kcd]=declaration[kcd];
						}
					}
				}
				kcrules[kci]=kc_sheetmethod(kc).rule(index);
				if(typeof(kc_auto_index)!="undefined") index=false;
			}
			return kcrules;
		}
		
		/*
		@title: Stylesheets Rules
		@description: return all rules of the result stylesheets
		@params: selector [string]
				 index [number]
		@return: object with boolean results
		*/
		kc_sheet.rule=function(selector,index){
			var kcrule={}
			var kccnt=0;
			var kccnt2=0;
			var crossrules={};
			var kcselectors={};
			var kcparents={}
			var kccsstext={};
			var kcruleindex={};
			
			for(var kci=0;kci<kc_sheet.length;kci++){
				/*Crossbrowser CSS Rules call*/
				if(kc_sheet[kci].cssRules){
					crossrules=kc_sheet[kci].cssRules;
				}else{
					crossrules=kc_sheet[kci].rules;
				}
				/*Internal rule methods and properties*/
				function setRuleOptions(){
					/*Get selector text*/
					kcselectors[kccnt]=crossrules[kcr].selectorText;
					/*Parent Style Sheet*/
					kcparents[kccnt]=kc_sheet[kci];
					/*Rule CSS Text*/
					if(crossrules[kcr].cssText){
						kccsstext[kccnt]=crossrules[kcr].cssText.split("{")[1].split("}")[0].replace(/^\s+|\s+$/g, '');
					}else{
						kccsstext[kccnt]=crossrules[kcr].style.cssText.replace(/^\s+|\s+$/g, '');
					}
					/*Rule Index*/
					kcruleindex[kccnt]=kcr;
					
				}
				/*Collect CSS Rules*/
				for(var kcr=0;kcr<crossrules.length;kcr++){
					if(typeof(selector)=="undefined"){
						if(crossrules[kcr].selectorText){
							kcrule[kccnt]=crossrules[kcr];
							setRuleOptions();
							kccnt++;
						}
					}
					else if(typeof(selector)=="number"){
						if(kcr==0){
							kcrule[kccnt]=crossrules[selector];
							setRuleOptions();
							kccnt++;
						}
					}
					else if(typeof(selector)=="string"){
						if(crossrules[kcr].selectorText){
							if(crossrules[kcr].selectorText.toLowerCase().match(selector.toLowerCase())){
								if(typeof(index)=="undefined"){
									kcrule[kccnt]=crossrules[kcr];
									setRuleOptions();
									kccnt++;
								}else{
									if(kccnt2==index){
										kcrule[kccnt]=crossrules[kcr];
										setRuleOptions();
										kccnt++;
									}
									kccnt2++;
								}
							}
						}
					}
				}
			}
			
			/*
			@title: Rules Length
			@description: return the amount of selected rules
			*/
			kcrule.length=kccnt;
			
			/*
			@title: Rules Index
			@description: return the amount of selected rules
			@params: index [number]
			@return: object with index positions of the selected rules
			*/
			kcrule.index=function(index){
				if(typeof(index)=="undefined"){
					return kcruleindex;
				}else{
					return kcruleindex[index];
				}
			}
			
			/*
			@title: Rules Selector
			@description: return the selector strings of selected rules
			@params: index [number]
			@return: object with selector strings
			*/
			kcrule.selector=function(index){
				if(typeof(index)=="undefined"){
					return kcselectors;
				}else{
					return kcselectors[index];
				}
			}
			
			/*
			@title: Rules Selector
			@description: return the parent stylesheets of selected rules
			@params: index [number]
			@return: collection of stylesheets DOM objects
			*/
			kcrule.parent=function(index){
				var kcparents={};
				for(var kcr=0;kcr<kcrule.length;kcr++){
					kcparents[kcr]=kcrule[kcr].parentStyleSheet
				}
				if(typeof(index)=="undefined"){
					return kcparents;
				}else{
					return kcparents[index];
				}
			}
			
			/*
			@title: Rules CSS Text
			@description: return the CSS Text of selected rules
			@params: index [number]
			@return: object with CSS declaration strings
			*/
			kcrule.cssText=function(index){
				if(typeof(index)=="undefined"){
					return kccsstext;
				}else{
					return kccsstext[index];
				}
			}
			
			/*
			@title: Set Rule Styles
			@description: set up new declarations for the selected rules
			@params: declaration [string | object]
					 index [number]
			@return: object with the modified rules
			*/
			kcrule.set=function(declaration,index){
				var kcrules={};
				if(typeof(declaration)=="object"){
					for(var kcr=0;kcr<kcrule.length;kcr++){
						for(var kcdecl in declaration){
							if(typeof(index)=="undefined"){
								kcrule[kcr].style[kcdecl]=declaration[kcdecl];
								kcrules[kcr]=kcrule[kcr];
							}else{
								if(index==kcr){
									kcrule[kcr].style[kcdecl]=declaration[kcdecl];
									kcrules[kcr]=kcrule[kcr];
								}
							}
						}
					}
				}else if(typeof(declaration)=="string"){
					var each_decl=declaration.split(";");//we split the different declarations
					for(elem in each_decl){
						var decl_prop=each_decl[elem].split(":");//then we split each property-value pair
						var decl_left=decl_prop[0].split("-");//now, we have to transform the CSS properties names, to valid javaScript ones
						for(var ditem=0;ditem<decl_left.length;ditem++){
							if(ditem>0){
								decl_left[ditem]=decl_left[ditem].charAt(0).toUpperCase() + decl_left[ditem].slice(1);//Instead of the dash , JS uses Camel Cased CSS declarations. here, we make that change.
							}
						}
						decl_left=decl_left.join("");//Now we join all together to construct the new JS valid css property
						/* Finally, we apply the new styles */
						if(decl_prop[1]){
							for(var kcr=0;kcr<kcrule.length;kcr++){
								if(typeof(index)=="undefined"){
									kcrule[kcr].style[decl_left]=decl_prop[1];
									kcrules[kcr]=kcrule[kcr];
								}else{
									if(index==kcr){
										kcrule[kcr].style[decl_left]=decl_prop[1];
										kcrules[kcr]=kcrule[kcr];
									}
								}
							}
						}
					}
				}
				return kcrules;
			}
			
			/*
			@title: Unset Rules
			@description: removes the selected rules
			@params: index [number]
			@return: success [boolean]
			*/
			kcrule.unset=function(index){
				if(typeof(index)=="undefined"){
					var kcsheethref="";
					for(var kcr=0;kcr<kcrule.length;kcr++){
						if(kcsheethref==kcrule.parent(kcr).href){
							kcsheethref=kcrule.parent(kcr).href;
							kcrule.parent(kcr).deleteRule(kcrule.index(kcr)-1);
						}else{
							kcsheethref=kcrule.parent(kcr).href;
							kcrule.parent(kcr).deleteRule(kcrule.index(kcr));
						}
					}
					return true;
				}else{
					for(var kcr=0;kcr<kcrule.length;kcr++){
						if(kcr==index){
							kcrule.parent(kcr).deleteRule(kcrule.index(kcr));
						}
					}
					return true;
				}
			}
			
			return kcrule;
		}
		
		
		return kc_sheet;
	}
}
shepherd=new kcCSShepherd();
sheet=shepherd.sheet();